/**
 * Wrapper class for autocomplete plugin upon JUI autocomplete widget
 * @author Smyle
 * @requires
 * qui.autocomplete 0.0.1+
 */
(function($, undefined) {
    $.widget("qui.suggest", $.qui.autocomplete, {
        version: '0.0.1',
        options: {
            // 请求地址
            url: '',

            // 请求类型
            method: 'get',

            // 是否自动选择地一条
            // autoFocus: true,

            // 是否可以多选
            multiple: true,

            // 是否校验结果
            validate: true,

            // 是否显示菜单为宫格结构
            gridMenu: false,

            multipleValid: false,

            // 当validate为true时，控制onblur时是否清空无效结果
            clearInvalid: true,

            noResult: '对不起，没有这个结果',

            // 一个结果时回调函数
            onOneResult: null,

            onMoreResult: null,

            onNoResult: null,

            // ajax额外参数
            otherParam: {},

            // 是否添加页脚
            needFooter: true,

            // 标签属性
            labelKey: 'label',

            // 关键字属性
            keywordKey: 'word',

            // 标签id属性
            valueKey: 'id',

            // 开启filter
            autoFilter: false,

            // 强制验证是否再autocomplete列表
            mustInAutoComplete: true,

            // tag插入顺序，"after"或"before"
            tagInsertOrder: 'after',

            // 强制验证tag id，若无则忽略
            forceTagId: true,

            // 默认基于行布局(row)，目前支持row, grid
            layout: 'row',

            // extendable ajax used when request is sent out
            ajaxSettings: {

            },
            stopSuggest:false,
            // 组件初始化时调用解析
            parseValue: function() {
                var val = this.element.val(),
                    ret = [],
                    items = null,
                    itemData = null,
                    options = this.options;

                if (val) {
                    items = val.split(';');
                    $.each(
                        items,
                        function(i, item) {
                            item = item.split(',');
                            itemData = {};
                            itemData[options.labelKey] = item[1];
                            itemData[options.valueKey] = item[0];
                            ret.push(itemData);
                        }
                    );
                }
                this._value('');
                return ret;
            },

            // 最终处理ajax的params
            processParams: function(params) {
                return params;
            },

            /**
             * @desc handler for create event
             */
            create: function(event, ui) {
                $(this).suggest('init');
            },

            /**
             * @desc handler to reorganize raw data, the return value will
             * be used to render the suggest list
             * @return {Array}
             */
            process: function(json) {
                var ret = [],
                    data = $.isArray(json) ? json : json.data,
                    self = this,
                    options = self.options,
                    itemData = null;
                if (!data) {
                    return [];
                }
                $.map(data, function(item) {
                    if ('string' === typeof item) {
                        itemData = {};

                        itemData[options.labelKey]
                            = itemData[options.valueKey]
                            = itemData[self._displayKey]
                            = itemData['label']
                            = itemData['value']
                            = item;

                        ret.push(itemData);
                    } else {
                        item[self._displayKey] = item[options.labelKey];
                        item['label'] = item[options.labelKey];
                        item['value'] = item[options.labelKey];
                        ret.push(item);
                    }
                });
                return ret;
            },

            /**
             * @desc used to highlight key word, the highlight should process
             * the label key and save it back in the storeKey， the storekey
             * is generally the displayed key defined by suggest plugin
             */
            highlight: function(data, storeKey, term) {
                var self = this,
                    options = self.options;
                data.forEach(function(item, i) {
                    var label = null;
                    if ('string' !== typeof item) {
                        key = options.labelKey;
                        label = item[key];
                        if (!label || !term) {
                            return;
                        }
                        try {
                            item[self._displayKey] = item[key].replace(new RegExp('(' + term + ')', 'ig'), '<b>$1</b>');
                        } catch (ex) {}
                    } else {
                        data[i] = item.replace(new RegExp('(' + term + ')', 'ig'), '<b>$1</b>');
                    }
                });
            }
        },

        _renderMenu: function(ul, items){
            // set the style of UL according to the param 'layout'
            if ("grid" == this.options.layout) {
                ul.addClass('qui-grid-celllayout');
            }
            this._super(ul, items);
        },

        /**
         * return an array of processed items which is used to render the suggest pop list
         *  @return {Array}
         */
        getResultData: function() {
            return this.result;
        },

        /**
         * @desc send ajax request to remote suggest service
         */
        _getSuggestData: function(url, method, params, callback) {
            $.ajax( $.extend(
                {
                    url: url,
                    dataType: 'json',
                    data: this.options.processParams ? this.options.processParams(params) : params,
                    cache: false,
                    method: method,
                    success: function(data) {
                        if (callback) {
                            callback.call(this, data);
                        }
                    },
                    error: function(data) {
                        if (callback) {
                            callback.call(this, data);
                        }
                    }
                }, this.options.ajaxSettings || {}
            ));
        },

        /**
         * entrance for suggest to handle the request process
         * @param {Function} requset JSON in format of { term: value }
         * @param {Function} response the function to handle the response of request
         * @param {Object} data raw array used to render the suggest list
         */
        _handleResponse: function(request, response, data) {
            var self = this,
                options = self.options,
                term = $.trim(request.term),
                dataProcess = options.process,
                ret = dataProcess.call(self, data, term);

            ret = options.autoFilter ? $.ui.autocomplete.filter(ret, term) : ret;

            if (options.highlight) {
                options.highlight.call(self, ret, self._displayKey, term);
            }

            self.result = ret;
            response(ret);
        },

        /**
         * override original JUI autocomplete source initializer
         */
        _initSource: function() {
            var array, self = this;
            if ($.isArray(self.options.source)) {
                array = self.options.source;
                self.source = function(request, response) {
                    self._handleResponse(request, response, array);
                };
            } else if (typeof this.options.source === "string") {
                self.options.url = url = self.options.source;
                self.source = self.__source;
            } else {
                self.source = self.options.source;
            }
        },

        /**
         * invoked when there is a need to send an ajax suggest
         * @param {Object} request JSON in format of { term: value }
         * @param {Function} response the function to handle the response of request
         */
        __source: function(request, response) {
            var self = this,
                options = self.options,
                term = $.trim(request.term),
                url = null,
                getParam = null,
                param = {};

            if (!term) {
                return null;
            }


            if (!options.ignoreWord) {
                //传递 word  term
                param[options.keywordKey ? options.keywordKey : 'word'] = term;
            }

            param = $.extend(true, options.otherParam, param);

            url = options.url;
            getParam = options.getParam;
            if (getParam) {
                if ($.isFunction(options.getParam)) {
                    param = $.extend(true, param, getParam.call(self, term));
                } else if ($.isPlainObject(getParam)) {
                    param = $.extend(true, param, getParam);
                }
            }
            if(options.stopSuggest){
                return
            }
            self._getSuggestData(url, options.method, param, $.proxy(self._handleResponse, self, request, response));
        },

        _create: function() {
            var $this = this.element;
            $this.wrap('<span class="ui-front ui-suggest"></span>');
            this._super();
            $this.on('suggestresponse', function(event, ui) {
                var content = ui.content;
                $this.suggest('validate', content);
            }).on('suggestselect', function(event, ui) {
                return $this.suggest('setValue', ui.item);
            }).on('suggestsearch', function(event, ui) {
                return $this.suggest('multiplesearch');
            });
        }
    });
}(jQuery));